package com.ihr360.payroll.service.attendancereport.impl;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.ihr360.attendance.AttendancePeriodReport;
import com.ihr360.attendance.AttendanceReportFixedPart;
import com.ihr360.common.DateRange;
import com.ihr360.commons.exception.Ihr360Exception;
import com.ihr360.commons.lang.CollectionUtils;
import com.ihr360.commons.lang.DateUtils;
import com.ihr360.commons.lang.PageUtil;
import com.ihr360.commons.lang.StringUtils;
import com.ihr360.commons.vo.PageData;
import com.ihr360.excel.ExcelUtil;
import com.ihr360.excel.cellstyle.ExcelCellStyle;
import com.ihr360.excel.cellstyle.ExcelCellStyleFactory;
import com.ihr360.excel.entity.CorrectSpreadsheetRowEntity;
import com.ihr360.excel.entity.ExportParams;
import com.ihr360.excel.entity.ImportParams;
import com.ihr360.excel.vo.CustomSpreadSheetValidateResult;
import com.ihr360.excel.vo.ImportRequest;
import com.ihr360.excel.vo.SpreadSheetRow;
import com.ihr360.excel.vo.SpreadSheetValidInterruptError;
import com.ihr360.excel.vo.SpreadSheetValidatorError;
import com.ihr360.excel.vo.SpreadSheetValidatorRequest;
import com.ihr360.payroll.dao.AttendanceBillRepository;
import com.ihr360.payroll.dao.AttendanceMonthlyReportSummaryRepository;
import com.ihr360.payroll.dao.StaffPayrollInfoJournalRepository;
import com.ihr360.payroll.importVo.AttendanceBillImportVo;
import com.ihr360.payroll.model.dto.attendance.report.AttendanceBill;
import com.ihr360.payroll.model.dto.attendance.report.AttendanceMonthlyReport;
import com.ihr360.payroll.model.dto.attendance.report.AttendanceMonthlyReportSummary;
import com.ihr360.payroll.model.dto.salary.embeddable.StaffInfoSnapshot;
import com.ihr360.payroll.model.dto.staff.StaffPayrollInfoJournal;
import com.ihr360.payroll.request.AttendanceBillRequest;
import com.ihr360.payroll.response.attendance.ReportTypeResponse;
import com.ihr360.payroll.service.attendancereport.AttendanceBillService;
import com.ihr360.payroll.service.attendancereport.AttendanceMonthlyReportService;
import com.ihr360.payroll.service.attendancereport.AttendanceMonthlyReportSummaryService;
import com.ihr360.payroll.type.AttendanceState;
import com.ihr360.rest.reposity.SimpleRestReposity;
import com.ihr360.rest.service.AbstractSimpleRestServiceImpl;
import com.ihr360.shared.basicstaffinfo.dao.SyncedStaffInfoRepository;
import com.ihr360.shared.basicstaffinfo.dto.SyncedBasicStaffInfo;
import com.ihr360.type.StaffStatus;
import com.ihr360.validation.ValidationUtils;
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class AttendanceBillServiceImpl extends AbstractSimpleRestServiceImpl<AttendanceBill, Long> implements AttendanceBillService {

    private static final Logger logger = LoggerFactory.getLogger(AttendanceBillServiceImpl.class);
    //休假类型
    private static final String VACATION_BILL_TYPE = "VACATION";
    //加班类型
    private static final String OVERTIME_BILL_TYPE = "OVERTIME";

    private static final Map<String, String> vacationTypeMap = new LinkedHashMap<>();

    private static final Map<String, String> overtimeTypeMap = new LinkedHashMap<>();

    static {
        vacationTypeMap.put(AttendanceReportFixedPart.Field.UNPAID_LEAVE_COUNT, "事假");
        vacationTypeMap.put(AttendanceReportFixedPart.Field.ANNUAL_LEAVETIME, "年假");
        vacationTypeMap.put(AttendanceReportFixedPart.Field.SICK_LEAVE_COUNT, "病假");
        vacationTypeMap.put(AttendanceReportFixedPart.Field.MATERNITY_COUNT, "产假");
        vacationTypeMap.put(AttendanceReportFixedPart.Field.REST_HOURS, "调休");

        overtimeTypeMap.put(AttendanceReportFixedPart.Field.OT_HOURS_150, "工作日加班");
        overtimeTypeMap.put(AttendanceReportFixedPart.Field.OT_HOURS_200, "休息日加班");
        overtimeTypeMap.put(AttendanceReportFixedPart.Field.OT_HOURS_300, "节假日加班");
    }

    public static final String SUMMARY_ID = "summaryId";

    private static final String REPORT_TYPE = "单据类型";
    private static final String REPORT_DATE = "日期";
    private static final String ITEM = "时长";
    private static final String REMARK = "事由";
    private static final String APPLY_DATE = "申请时间";

    @Autowired
    private AttendanceBillRepository attendanceBillRepository;

    @Autowired
    private AttendanceMonthlyReportSummaryService attendanceMonthlyReportSummaryService;


    @Autowired
    private AttendanceMonthlyReportService attendanceMonthlyReportService;

    @Autowired
    private SyncedStaffInfoRepository syncedStaffInfoRepository;

    @Autowired
    private StaffPayrollInfoJournalRepository staffPayrollInfoJournalRepository;

    @Autowired
    private AttendanceMonthlyReportSummaryRepository attendanceMonthlyReportSummaryRepository;

    //private final MessageSourceAccessor messageSource;


    @Override
    public SimpleRestReposity<AttendanceBill, Long> getSimpleRestReposity() {
        return attendanceBillRepository;
    }

    @Override
    public Map<String, List<AttendancePeriodReport>> getPeriodReportOfStaffs(String companyId, Long salaryPlanId, Map<String, List<DateRange>> staffs, DateRange attendanceRange, int year, int month) {

        ValidationUtils.rejectIfEmpty(companyId, null, "无效的公司标识");
        ValidationUtils.rejectIfEmpty(staffs, null, "员工列表为空");

        //汇总信息必须锁定后才可以查询取数
        AttendanceMonthlyReportSummary summary = attendanceMonthlyReportSummaryRepository.findByCompanyIdAndYearAndMonthAndSalaryPlanId(companyId, year, month, salaryPlanId);
        if (summary == null || !AttendanceState.LOCKED.equals(summary.getState())) {
            return Collections.emptyMap();
        }
        Date startDate = attendanceRange.getStart();
        Date endDate = attendanceRange.getEnd();

        List<AttendanceBill> dailyReports = attendanceBillRepository.findDailyReportOfStaffsInAPeriod(companyId, salaryPlanId, startDate, endDate, staffs.keySet());
        if (CollectionUtils.isEmpty(dailyReports)) {
            return Collections.emptyMap();
        }

        Map<String, List<AttendancePeriodReport>> periodReportsMap = new HashMap<>(3);

        Map<String, List<AttendanceBill>> dailyReportsMap = dailyReports.stream()
                .collect(Collectors.groupingBy(r -> r.getStaffInfo().getStaffId()));

        List<AttendancePeriodReport> periodReports = new ArrayList<>(3);
        //考勤日报是否只保存异常的数据呢？？？？
        //如果查不到考勤日报是否意味着这个人实际是没有分段考勤。
        for (Map.Entry<String, List<AttendanceBill>> entry : dailyReportsMap.entrySet()) {
            String staffId = entry.getKey();
            List<AttendanceBill> dailyReportList = entry.getValue();
            if (CollectionUtils.isEmpty(dailyReportList)) {
                //TODO: 是否需要 添加日志记录
                continue;
            }
            dailyReportList = dailyReportList.stream().sorted((r1, r2) -> r1.getReportDate().compareTo(r2.getReportDate())).collect(Collectors.toList());
            List<DateRange> dateRanges = staffs.get(staffId);
            for (final DateRange range : dateRanges) {
                final Date fromDate = range.getStart();
                final Date toDate = range.getEnd().after(attendanceRange.getEnd()) ? attendanceRange.getEnd() : range.getEnd();
                List<AttendanceBill> reportInRange = dailyReportList.stream().filter(s -> DateUtils.isBetween(s.getReportDate(), fromDate, toDate))
                        .collect(Collectors.toList());
                if (CollectionUtils.isEmpty(reportInRange)) {
                    //TODO: 是否需要 添加日志记录
                    continue;
                }
                AttendancePeriodReport periodReport = toPeriodReport(staffId, DateRange.build(fromDate, toDate), reportInRange);
                periodReports.add(periodReport);
            }

            if (CollectionUtils.isNotEmpty(periodReports)) {
                periodReportsMap.put(staffId, periodReports);
            }
        }
        return periodReportsMap;
    }

    public AttendancePeriodReport toPeriodReport(String staffId, DateRange dateRange, List<AttendanceBill> reportInRange) {
        //String staffId,String staffName, int year, int month, DateRange dateRange, Map<String, Double> items
        int year = dateRange.getFromYear();
        int month = dateRange.getFromMonth();
        Map<String, Double> items = convert(reportInRange);
        String staffName = null;
        if (!CollectionUtils.isEmpty(reportInRange)) {
            AttendanceBill report = reportInRange.get(0);
            staffName = report.getStaffInfo().getStaffName();
        }
        if (CollectionUtils.isEmpty(items)) {
            return new AttendancePeriodReport(staffId, staffName, year, month, dateRange, Collections.emptyMap());
        }
        AttendanceReportFixedPart fixedPart = new AttendanceReportFixedPart();
        Map<String, Double> flexPart = new HashMap<>();
        for (Map.Entry<String, Double> entry : items.entrySet()) {
            switch (entry.getKey()) {
                case AttendanceReportFixedPart.Field.UNPAID_LEAVE_COUNT://事假
                    fixedPart.setUnpaidleavecnt(entry.getValue());
                    break;
                case AttendanceReportFixedPart.Field.ANNUAL_LEAVETIME://年假
                    fixedPart.setAnnualleavetime(entry.getValue());
                    break;
                case AttendanceReportFixedPart.Field.SICK_LEAVE_COUNT://病假
                    fixedPart.setSickleavecnt(entry.getValue());
                    break;
                case AttendanceReportFixedPart.Field.MATERNITY_COUNT://产假
                    fixedPart.setMaternitycnt(entry.getValue());
                    break;
                case AttendanceReportFixedPart.Field.REST_HOURS://调休
                    fixedPart.setResthours(entry.getValue());
                    break;
                case AttendanceReportFixedPart.Field.OT_HOURS_150://工作日加班
                    fixedPart.setOthours150(entry.getValue());
                    break;
                case AttendanceReportFixedPart.Field.OT_HOURS_200://休息日加班
                    fixedPart.setOthours200(entry.getValue());
                    break;
                case AttendanceReportFixedPart.Field.OT_HOURS_300://节假日加班
                    fixedPart.setOthours300(entry.getValue());
                    break;
                default://自定义假期
                    flexPart.put(entry.getKey(), entry.getValue());
                    break;
            }
        }
        AttendancePeriodReport attendancePeriodReport = new AttendancePeriodReport(staffId, staffName, year, month, dateRange, flexPart);
        attendancePeriodReport.setFixedPart(fixedPart);
        return attendancePeriodReport;
    }

    //将区间日报转变为月报
    public Map<String, Double> convert(List<AttendanceBill> reportInRange) {
        Map<String, Double> items = new HashMap<>();
        if (CollectionUtils.isEmpty(reportInRange)) {
            return Collections.emptyMap();
        }
        for (AttendanceBill attendanceBill : reportInRange) {
            if (attendanceBill == null) {
                continue;
            }
            String reportType = attendanceBill.getReportType();
            Double item = items.get(reportType);
            if (item == null) {
                item = 0d;
            }
            item = item + attendanceBill.getItem();
            items.put(reportType, item);
        }
        return items;
    }

    @Override
    public List<AttendanceBill> getStaffDailyReport(String staffId, String companyId, Long summaryId, String type) {
        List<AttendanceMonthlyReport> monthlyReportList = attendanceMonthlyReportService.getMonthlyReportList(companyId, summaryId);
        if (CollectionUtils.isEmpty(monthlyReportList)) {
            return Lists.newArrayList();
        }
        List<Long> monthlyReportIdList = monthlyReportList.stream().map(AttendanceMonthlyReport::getId).collect(Collectors.toList());
        return attendanceBillRepository.findByCompanyIdAndStaffInfoStaffIdAndMonthlyReportIdInAndReportType(companyId, staffId, monthlyReportIdList, type);
    }

    @Override
    public PageData<AttendanceBill> getStaffAllAttendanceBill(String companyId, AttendanceBillRequest attendanceBillRequest) {
        List<AttendanceMonthlyReport> monthlyReportList = attendanceMonthlyReportService.getMonthlyReportList(companyId, attendanceBillRequest.getSummaryId());
        if (CollectionUtils.isEmpty(monthlyReportList)) {
            return new PageData<>(0, 0, Lists.newArrayList());
        }
        List<Long> monthlyReportIdList = monthlyReportList.stream().map(AttendanceMonthlyReport::getId).collect(Collectors.toList());
        //查询考勤月报信息
        Pageable pageable = PageUtil.getPageable(attendanceBillRequest.getPage(), attendanceBillRequest.getSize());
        Page<AttendanceBill> page = this.search(getSpecification(companyId, attendanceBillRequest, monthlyReportIdList, null), pageable, false);
        if (page == null || CollectionUtils.isEmpty(page.getContent())) {
            return new PageData<>(0, 0, Lists.newArrayList());
        }
        return new PageData<>(page.getTotalPages(), page.getTotalElements(), page.getContent());
    }

    @Override
    public PageData<AttendanceBill> getAllAttendanceBill(String companyId, AttendanceBillRequest attendanceBillRequest) {
        Pageable pageable = PageUtil.getPageable(attendanceBillRequest.getPage(), attendanceBillRequest.getSize());
        List<String> staffIdList = Lists.newArrayList();
        AttendanceMonthlyReportSummary summary = attendanceMonthlyReportSummaryService.getOne(attendanceBillRequest.getSummaryId());
        List<AttendanceMonthlyReport> monthlyReportList = attendanceMonthlyReportService.getMonthlyReportList(companyId, attendanceBillRequest.getSummaryId());
        if (summary == null || CollectionUtils.isEmpty(monthlyReportList)) {
            return new PageData<>(0, 0, Lists.newArrayList());
        }
        List<Long> monthlyReportIdList = monthlyReportList.stream().map(AttendanceMonthlyReport::getId).collect(Collectors.toList());

        if (attendanceBillRequest.getIsAll() != null && !attendanceBillRequest.getIsAll()) {
            //查询有异动的人员列表
            Date startDate = DateUtils.getMinDateInDay(summary.getStartDate());
            Date endDate = DateUtils.getMaxDateInDay(summary.getEndDate());
            List<StaffPayrollInfoJournal> list = staffPayrollInfoJournalRepository.findByCompanyIdAndChangeTypeInAndEffectiveAtBetweenAndIsDeleted(companyId, AttendanceMonthlyReportServiceImpl.changeTypeList, startDate, endDate, false);
            if (CollectionUtils.isEmpty(list)) {
                return new PageData<>(0, 0, Lists.newArrayList());
            }
            staffIdList = list.stream().map(StaffPayrollInfoJournal::getStaffId).collect(Collectors.toList());
        }
        Page<AttendanceBill> page = this.search(getSpecification(companyId, attendanceBillRequest, monthlyReportIdList, staffIdList), pageable, false);
        if (page == null || CollectionUtils.isEmpty(page.getContent())) {
            return new PageData<>(0, 0, Lists.newArrayList());
        }
        return new PageData<>(page.getTotalPages(), page.getTotalElements(), page.getContent());
    }

    private Specification<AttendanceBill> getSpecification(String companyId, AttendanceBillRequest attendanceBillRequest, List<Long> monthlyReportIdList, List<String> staffIdList) {
        return (root, q, cb) -> {
            Predicate predicate = cb.conjunction();
            List<Expression<Boolean>> expressionList = predicate.getExpressions();
            expressionList.add(cb.equal(root.get("companyId"), companyId));
            //月报列表
            CriteriaBuilder.In<Long> reportIdIn = cb.in(root.get("monthlyReport").get("id"));
            monthlyReportIdList.forEach(reportIdIn::value);
            expressionList.add(reportIdIn);

            //expressionList.add(cb.equal(root.get("summary").get("Id"), summaryId));
            if (StringUtils.isNotBlank(attendanceBillRequest.getStaffId())) {
                expressionList.add(cb.equal(root.get("staffInfo").get("staffId"), attendanceBillRequest.getStaffId()));
            }
            if (StringUtils.isNotBlank(attendanceBillRequest.getStaffName())) {
                expressionList.add(cb.equal(root.get("staffInfo").get("staffName"), attendanceBillRequest.getStaffName()));
            }
            if (StringUtils.isNotBlank(attendanceBillRequest.getReportType())) {
                expressionList.add(cb.equal(root.get("reportType"), attendanceBillRequest.getStaffName()));
            }
            if (StringUtils.isNotBlank(attendanceBillRequest.getType())) {
                //类型列表
                List<String> typeList = this.getReportTypeList(attendanceBillRequest.getSummaryId(), attendanceBillRequest.getType());
                CriteriaBuilder.In<String> in = cb.in(root.get("reportType"));
                typeList.forEach(in::value);
                expressionList.add(in);
            }
            if (attendanceBillRequest.getIsAll() != null && !attendanceBillRequest.getIsAll() && CollectionUtils.isNotEmpty(staffIdList)) {
                CriteriaBuilder.In<String> in = cb.in(root.get("staffInfo").get("staffId"));
                staffIdList.forEach(in::value);
                expressionList.add(in);
            }
            return predicate;
        };
    }


    @Override
    public Map<String, List<AttendanceBill>> getBillTypeMap(String companyId, List<Long> reportIdList) {
        Map<String, List<AttendanceBill>> map = Maps.newHashMap();
        if (CollectionUtils.isEmpty(reportIdList)) {
            return map;
        }
        List<AttendanceBill> attendanceBillList = attendanceBillRepository.findByCompanyIdAndMonthlyReportIdInOrderByReportDate(companyId, reportIdList);
        if (CollectionUtils.isEmpty(attendanceBillList)) {
            return map;
        }
        for (AttendanceBill attendanceBill : attendanceBillList) {
            String key = attendanceBill.getStaffInfo().getStaffId() + attendanceBill.getReportType();
            List<AttendanceBill> list = map.get(key);
            if (CollectionUtils.isEmpty(list)) {
                list = Lists.newArrayList();
            }
            list.add(attendanceBill);
            map.put(key, list);
        }
        return map;
    }

    @Override
    public List<ReportTypeResponse> queryReportList(Long summaryId, String type) {
        List<ReportTypeResponse> list = Lists.newArrayList();
        Map<String, String> map = new HashMap<>();
        AttendanceMonthlyReportSummary summary = attendanceMonthlyReportSummaryService.getOne(summaryId);
        if (summary == null) {
            throw new Ihr360Exception(null, "考勤汇总记录不存在");
        }
        if (StringUtils.isBlank(type)) {
            throw new Ihr360Exception(null, "单据类型不可为空");
        }
        if (VACATION_BILL_TYPE.equals(type)) {//假期类型
            //自定义假期
            if (summary.getFlexPartHeader() != null && MapUtils.isNotEmpty(summary.getFlexPartHeader().getHeader())) {
                Map<String, String> flexPart = summary.getFlexPartHeader().getHeader();
                map.putAll(flexPart);
            }
            map.putAll(vacationTypeMap);
        } else {//加班类型
            map.putAll(overtimeTypeMap);
        }
        if (MapUtils.isNotEmpty(map)) {
            for (Map.Entry<String, String> entry : map.entrySet()) {
                ReportTypeResponse response = new ReportTypeResponse();
                response.setLabel(entry.getKey());
                response.setData(entry.getValue());
                list.add(response);
            }
        }
        return list;
    }

    /**
     * 根据类型查询单据类型列表
     */
    private List<String> getReportTypeList(Long summaryId, String type) {
        List<String> list = Lists.newArrayList();
        AttendanceMonthlyReportSummary summary = attendanceMonthlyReportSummaryService.getOne(summaryId);
        if (summary == null) {
            throw new Ihr360Exception(null, "考勤汇总记录不存在");
        }
        if (StringUtils.isBlank(type)) {
            throw new Ihr360Exception(null, "单据类型不可为空");
        }
        if (VACATION_BILL_TYPE.equals(type)) {//假期类型
            //自定义假期
            if (summary.getFlexPartHeader() != null && MapUtils.isNotEmpty(summary.getFlexPartHeader().getHeader())) {
                Map<String, String> flexPart = summary.getFlexPartHeader().getHeader();
                for (Map.Entry<String, String> entry : flexPart.entrySet()) {
                    list.add(entry.getKey());
                }
            }
            list.addAll(vacationTypeMap.keySet());
        } else {//加班类型
            list.addAll(overtimeTypeMap.keySet());
        }
        return list;
    }

    private List<String> getReportTypeNameList(Long summaryId) {
        List<String> typeList = Lists.newArrayList();
        typeList.addAll(vacationTypeMap.values());
        //typeList.addAll(overtimeTypeMap.values());
        //自定义部分
        AttendanceMonthlyReportSummary summary = attendanceMonthlyReportSummaryService.getOne(summaryId);
        if (summary == null) {
            throw new Ihr360Exception(null, "考勤汇总记录不存在");
        }
        if (summary.getFlexPartHeader() != null && MapUtils.isNotEmpty(summary.getFlexPartHeader().getHeader())) {
            Map<String, String> map = summary.getFlexPartHeader().getHeader();
            for (Map.Entry<String, String> entry : map.entrySet()) {
                typeList.add(entry.getValue());
            }
        }
        return typeList;
    }

    @Override
    public void excelTemplateDownload(OutputStream out, Long summaryId) {
        ExportParams<List<Object>> exportParams = new ExportParams<>();
        Map<String, String> headerMap = new LinkedHashMap<>();
        Map<String, List<String>> dropDownsMap = new HashMap<>();
        Map<String, ExcelCellStyle> headerStyleMap = new HashMap<>();

        headerMap.put("staffName", "姓名");
        headerMap.put("mobile", "手机号");
        headerMap.put("reportType", REPORT_TYPE);
        headerMap.put("reportDate", REPORT_DATE);
        headerMap.put("item", ITEM);
        headerMap.put("remark", REMARK);
        headerMap.put("applyDate", APPLY_DATE);

        List<String> typeList = this.getReportTypeNameList(summaryId);
        dropDownsMap.put("reportType", typeList);

        headerStyleMap.put("staffName", ExcelCellStyleFactory.createRequiredHeaderCellStyle());
        headerStyleMap.put("mobile", ExcelCellStyleFactory.createRequiredHeaderCellStyle());
        headerStyleMap.put("reportType", ExcelCellStyleFactory.createRequiredHeaderCellStyle());
        headerStyleMap.put("reportDate", ExcelCellStyleFactory.createRequiredHeaderCellStyle());
        headerStyleMap.put("item", ExcelCellStyleFactory.createRequiredHeaderCellStyle());

        exportParams.setHeaderMap(headerMap);
        exportParams.setDropDownsMap(dropDownsMap);
        exportParams.setHeaderStyleMap(headerStyleMap);

        ExcelUtil.exportExcel(exportParams, out);
    }


    @Override
    @Transactional
    public void importAttendanceBill(String companyId, ImportRequest importRequest) {
        ImportParams<AttendanceBillImportVo> importParams = new ImportParams<>();
        importParams.setImportType(AttendanceBillImportVo.class);
        try {
            List<CorrectSpreadsheetRowEntity> excelData = importRequest.getCorrectDatas();
            Map<String, Object> extraParams = importRequest.getExtraParams();
            Long summaryId = Long.parseLong(extraParams.get(SUMMARY_ID).toString());
            List<SyncedBasicStaffInfo> staffList = syncedStaffInfoRepository.findByCompanyIdAndStaffStatusNot(companyId, StaffStatus.DELETE);
            Map<String, SyncedBasicStaffInfo> staffMap = staffList.stream().collect(Collectors.toMap(SyncedBasicStaffInfo::getId, Function.identity()));
            AttendanceMonthlyReportSummary summary = attendanceMonthlyReportSummaryService.getOne(summaryId);
            if (summary == null) {
                throw new Ihr360Exception(null, "考勤汇总记录不存在");
            }
            List<AttendanceMonthlyReport> reportList = attendanceMonthlyReportService.getMonthlyReportList(companyId, summaryId);
            if (CollectionUtils.isEmpty(reportList)) {
                throw new Ihr360Exception(null, "考勤月报数据为空，无法导入考勤单据");
            }
            Map<String, AttendanceMonthlyReport> reportMap = reportList.stream().collect(Collectors.toMap(report -> report.getStaffInfo().getStaffId(), Function.identity()));
            int year = summary.getYear();
            int month = summary.getMonth();
            List<AttendanceBill> list = Lists.newArrayList();
            Map<String, String> flexPart = Maps.newHashMap();
            if (summary.getFlexPartHeader() != null && CollectionUtils.isNotEmpty(summary.getFlexPartHeader().getHeader())) {
                flexPart = summary.getFlexPartHeader().getHeader();
            }
            for (CorrectSpreadsheetRowEntity attendanceBillImportVo : excelData) {
                if (attendanceBillImportVo == null) {
                    continue;
                }
                SyncedBasicStaffInfo staffInfo = staffMap.get(attendanceBillImportVo.getStaffId());
                if (staffInfo == null) {
                    continue;
                }
                AttendanceBill attendanceBill = importToDto(staffInfo, attendanceBillImportVo, reportMap, year, month, flexPart);
                if (attendanceBill == null) {
                    continue;
                }
                list.add(attendanceBill);
            }
            attendanceBillRepository.save(list);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new Ihr360Exception(null, "保存数据失败");
        }
    }

    private AttendanceBill importToDto(SyncedBasicStaffInfo staffInfo, CorrectSpreadsheetRowEntity attendanceBillImportVo, Map<String, AttendanceMonthlyReport> reportMap, int year, int month, Map<String, String> flexPart) {
        AttendanceBill attendanceBill = new AttendanceBill();
        StaffInfoSnapshot staffInfoSnapshot = new StaffInfoSnapshot();
        BeanUtils.copyProperties(staffInfo, staffInfoSnapshot);
        staffInfoSnapshot.setStaffId(staffInfo.getId());
        attendanceBill.setStaffInfo(staffInfoSnapshot);
        attendanceBill.setYear(year);
        attendanceBill.setMonth(month);
        AttendanceMonthlyReport attendanceMonthlyReport = reportMap.get(staffInfo.getId());
        attendanceBill.setMonthlyReport(attendanceMonthlyReport);
        attendanceBill.setSalaryPlanId(attendanceMonthlyReport.getSalaryPlanId());
        Map<String, Object> data = attendanceBillImportVo.getData();
        if (data == null) {
            return null;
        }
        attendanceBill.setReportDate((Date) data.get(REPORT_DATE));//日期
        String reportType = data.get(REPORT_TYPE).toString();
        attendanceBill.setReportType(checkIsCustom(reportType, flexPart));//单据类型
        attendanceBill.setItem(Double.parseDouble(data.get(ITEM).toString()));//时长
        String remark = data.get(REMARK) == null ? null : data.get(REMARK).toString();
        attendanceBill.setRemark(remark);//事由
        Date applyDate = data.get(APPLY_DATE) == null ? null : (Date) data.get(REPORT_DATE);
        attendanceBill.setApplyDate(applyDate);//申请时间
        return attendanceBill;
    }

    //自定义假期处理
    private String checkIsCustom(String reportType, Map<String, String> flexPart) {
        if (vacationTypeMap.containsValue(reportType)) {
            for (Map.Entry<String, String> entry : vacationTypeMap.entrySet()) {
                if (entry.getValue().equals(reportType)) {
                    return entry.getKey();
                }
            }
        } else if (overtimeTypeMap.containsValue(reportType)) {
            for (Map.Entry<String, String> entry : overtimeTypeMap.entrySet()) {
                if (entry.getValue().equals(reportType)) {
                    return entry.getKey();
                }
            }
        } else {
            for (Map.Entry<String, String> entry : flexPart.entrySet()) {
                if (entry.getValue().equals(reportType)) {
                    return entry.getKey();
                }
            }
        }
        return reportType;
    }

    @Override
    public CustomSpreadSheetValidateResult validateExcelData(String companyId, String userId, Long summaryId, SpreadSheetValidatorRequest validatorRequest) {
        ValidationUtils.rejectIfEmpty(summaryId, "", "汇总信息不可为空");

        CustomSpreadSheetValidateResult result = new CustomSpreadSheetValidateResult();
        List<SpreadSheetRow> excelDatas = validatorRequest.getSpreadSheetDatas();
        if (CollectionUtils.isEmpty(excelDatas)) {
            return result;
        }
        AttendanceMonthlyReportSummary summary = attendanceMonthlyReportSummaryService.getOne(summaryId);
        if (summary == null) {
            SpreadSheetValidInterruptError interruptError = new SpreadSheetValidInterruptError();
            interruptError.setDefaultLogMsg("考勤汇总记录不存在");
            result.setInterruptError(interruptError);
            return result;
        }
        List<AttendanceMonthlyReport> reportList = attendanceMonthlyReportService.getMonthlyReportList(companyId, summaryId);
        if (CollectionUtils.isEmpty(reportList)) {
            SpreadSheetValidInterruptError interruptError = new SpreadSheetValidInterruptError();
            interruptError.setDefaultLogMsg("考勤月报数据为空，无法导入考勤单据");
            result.setInterruptError(interruptError);
            return result;
        }
        Map<String, AttendanceMonthlyReport> reportMap = reportList.stream().collect(Collectors.toMap(attendanceMonthlyReport -> attendanceMonthlyReport.getStaffInfo().getStaffId(), Function.identity()));
        List<SpreadSheetValidatorError> errors = Lists.newArrayList();
        for (SpreadSheetRow row : excelDatas) {
            if (!reportMap.containsKey(row.getStaffId())) {
                SpreadSheetValidatorError error = new SpreadSheetValidatorError();
                error.setMsg("员工在月报中不存在");
                error.setRowNum(row.getRowNum());
                errors.add(error);
                continue;
            }
        }
        return result;
    }
}